package http

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"regexp"
	"time"

	"mini-admin/internal/model/event"
	"mini-admin/internal/model/event/topic"
	"mini-admin/internal/mq"

	"github.com/GoAdminGroup/go-admin/engine"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"

	"mini-admin/internal/conf"
	"mini-admin/internal/database"
	"mini-admin/internal/model"
	"mini-admin/internal/pages"
	"mini-admin/internal/tables"
	"mini-admin/internal/types"
)

// Init Http Server
func Init(e *engine.Engine) {
	gin.SetMode(gin.ReleaseMode)
	gin.DefaultWriter = ioutil.Discard
	r := gin.Default()

	r.POST("/admin/form/wechat/commit", wechatCommit)
	r.POST("/admin/form/alipay/commit", alipayCommit)
	r.POST("/admin/form/bytedance/commit", bytedanceCommit)
	r.POST("/admin/form/message/publish", messagePublish)

	_ = e.AddGenerators(tables.Generators).
		AddGenerator("external_wechat_draft", tables.GetExternalWechatDraft).
		AddGenerator("external_wechat_template", tables.GetExternalWechatTemplate).
		AddGenerator("external_bytedance_draft", tables.GetExternalBytedanceDraft).
		AddGenerator("external_bytedance_template", tables.GetExternalBytedanceTemplate).
		Use(r)
	e.HTML("GET", "/admin", pages.GetContent)
	e.HTML("GET", "/admin/form/wechat/commit", pages.GetWechatCommitForm)
	e.HTML("GET", "/admin/form/alipay/commit", pages.GetAlipayCommitForm)
	e.HTML("GET", "/admin/form/bytedance/commit", pages.GetBytedanceCommitForm)
	e.HTML("GET", "/admin/form/message/publish", pages.GetMessagePublishForm)
	r.Static("/uploads", "./uploads")

	go func() {
		if err := r.Run(conf.Conf.HTTP.Port); err != nil {
			log.Printf("engine.Run error: %v", err)
			panic(err)
		}
	}()

}

func wechatCommit(c *gin.Context) {
	appID := c.PostForm("app_id")
	templateID := c.PostForm("template_id")
	extJSON := c.PostForm("ext_json")
	conn := database.New(conf.Conf.ORM)
	appVersion := new(model.MiniAppVersion)
	err := conn.Where("app_id = ? and platform = ?", appID, types.Wechat).First(appVersion).Error
	if err != nil {
		c.Abort()
	}
	appVersion.Status = "auditing"
	appVersion.Stage = "initialized"

	t := model.WechatTemplate{}
	if err = conn.Model(&model.WechatTemplate{}).
		Where("template_id = ?", templateID).
		First(&t).Error; err != nil {
		return
	}
	appVersion.AuditVersion = t.UserVersion
	branMiniApp := new(model.BrandMiniApp)
	if err = conn.Model(&model.BrandMiniApp{}).
		Where("app_id = ? and platform = ?", appID, types.Wechat).
		First(branMiniApp).Error; err != nil {
		return
	}
	ext := fmt.Sprintf(
		`{"brand_id": %d, "app_id": "%s"}`,
		branMiniApp.BrandID, appID)
	template := t.ToVO(fmt.Sprintf(`{"extAppid": "%s", "ext": %s}`, appID, ext))
	if extJSON != "" {
		reg := regexp.MustCompile(`\s+`)
		extJSON = reg.ReplaceAllString(extJSON, "")
		template.ExtJSON = extJSON
	}

	jobData, err := json.Marshal(template)
	if err != nil {
		return
	}
	appVersion.AuditVersion = t.UserVersion
	schedule := model.Schedule{
		RefID:      appVersion.ID,
		JobType:    "commit_code",
		JobData:    jobData,
		RetryCount: 0,
		JobStatus:  types.ScheduleTaskInit,
	}
	if err = conn.Transaction(func(tx *gorm.DB) (err error) {
		err = conn.Create(&schedule).Error
		if err != nil {
			return
		}
		err = conn.Save(&appVersion).Error
		if err != nil {
			return
		}
		return nil
	}); err != nil {
		return
	}
	nsq := mq.New(conf.Conf.NSQAddr, conf.Conf.NSQ)
	data, _ := json.Marshal(&event.TaskCommitCode{
		AppID:     appID,
		Platform:  types.Wechat,
		JobID:     schedule.ID,
		Biz:       jobData,
		Timestamp: time.Now().Unix(),
	})
	if err = nsq.Publish(topic.TaskCommitCode, data); err != nil {
		return
	}

}

func bytedanceCommit(c *gin.Context) {
	appID := c.PostForm("app_id")
	templateID := c.PostForm("template_id")
	extJSON := c.PostForm("ext_json")
	conn := database.New(conf.Conf.ORM)
	appVersion := new(model.MiniAppVersion)
	err := conn.Where("app_id = ? and platform = ?", appID, types.ByteDance).First(appVersion).Error
	if err != nil {
		c.Abort()
	}
	appVersion.Status = "auditing"
	appVersion.Stage = "initialized"

	t := model.BytedanceTemplate{}
	if err = conn.Model(&model.BytedanceTemplate{}).
		Where("template_id = ?", templateID).
		First(&t).Error; err != nil {
		return
	}
	appVersion.AuditVersion = t.UserVersion
	branMiniApp := new(model.BrandMiniApp)
	if err = conn.Model(&model.BrandMiniApp{}).
		Where("app_id = ? and platform = ?", appID, types.ByteDance).
		First(branMiniApp).Error; err != nil {
		return
	}
	ext := fmt.Sprintf(
		`{"brand_id": %d}`,
		branMiniApp.BrandID)
	template := t.ToVO(fmt.Sprintf(`{"extAppid": "%s", "ext": %s}`, appID, ext))
	if extJSON != "" {
		reg := regexp.MustCompile(`\s+`)
		extJSON = reg.ReplaceAllString(extJSON, "")
		template.ExtJSON = extJSON
	}

	jobData, err := json.Marshal(template)
	if err != nil {
		return
	}
	appVersion.AuditVersion = t.UserVersion
	schedule := model.Schedule{
		RefID:      appVersion.ID,
		JobType:    "commit_code",
		JobData:    jobData,
		RetryCount: 0,
		JobStatus:  0,
	}
	if err = conn.Transaction(func(tx *gorm.DB) (err error) {
		err = conn.Create(&schedule).Error
		if err != nil {
			return
		}
		err = conn.Save(&appVersion).Error
		if err != nil {
			return
		}
		return nil
	}); err != nil {
		return
	}
	nsq := mq.New(conf.Conf.NSQAddr, conf.Conf.NSQ)
	data, _ := json.Marshal(&event.TaskCommitCode{
		AppID:     appID,
		Platform:  types.ByteDance,
		JobID:     schedule.ID,
		Biz:       jobData,
		Timestamp: time.Now().Unix(),
	})
	if err = nsq.Publish(topic.TaskCommitCode, data); err != nil {
		return
	}
}

func alipayCommit(c *gin.Context) {
	appID := c.PostForm("app_id")
	templateID := c.PostForm("template_id")
	extJSON := c.PostForm("ext_json")
	conn := database.New(conf.Conf.ORM)
	appVersion := new(model.MiniAppVersion)
	err := conn.Where("app_id = ? and platform = ?", appID, types.Alipay).First(appVersion).Error
	if err != nil {
		c.Abort()
	}
	appVersion.Status = "auditing"
	appVersion.Stage = "initialized"

	t := model.AlipayTemplate{}
	if err = conn.Model(&model.AlipayTemplate{}).
		Where("template_id = ?", templateID).
		First(&t).Error; err != nil {
		return
	}
	appVersion.AuditVersion = t.TemplateVersion
	branMiniApp := new(model.BrandMiniApp)
	if err = conn.Model(&model.BrandMiniApp{}).
		Where("app_id = ? and platform = ?", appID, types.Alipay).
		First(branMiniApp).Error; err != nil {
		return
	}
	Ext := struct {
		ExtAppID  string                 `json:"extAppid"`
		Ext       map[string]interface{} `json:"ext"`
		ExtEnable bool                   `json:"extEnable,omitempty"`
	}{
		ExtAppID: appVersion.AppID,
		Ext: map[string]interface{}{
			"brand_id": branMiniApp.BrandID,
		},
		ExtEnable: true,
	}
	ext, _ := json.Marshal(Ext)
	template := t.ToVO(string(ext))
	if extJSON != "" {
		reg := regexp.MustCompile(`\s+`)
		extJSON = reg.ReplaceAllString(extJSON, "")
		template.Ext = extJSON
	}

	jobData, err := json.Marshal(template)
	if err != nil {
		return
	}
	appVersion.AuditVersion = t.AppVersion
	schedule := model.Schedule{
		RefID:      appVersion.ID,
		JobType:    "commit_code",
		JobData:    jobData,
		RetryCount: 0,
		JobStatus:  0,
	}
	if err = conn.Transaction(func(tx *gorm.DB) (err error) {
		err = conn.Create(&schedule).Error
		if err != nil {
			return
		}
		err = conn.Save(&appVersion).Error
		if err != nil {
			return
		}
		return nil
	}); err != nil {
		return
	}

	producer := mq.New(conf.Conf.NSQAddr, conf.Conf.NSQ)
	data, _ := json.Marshal(&event.TaskCommitCode{
		AppID:     appID,
		Platform:  types.Alipay,
		JobID:     schedule.ID,
		Biz:       jobData,
		Timestamp: time.Now().Unix(),
	})
	if err = producer.Publish(topic.TaskCommitCode, data); err != nil {
		return
	}

}

func messagePublish(c *gin.Context) {
	producer := mq.New(conf.Conf.NSQAddr, conf.Conf.NSQ)
	if err := producer.Publish(c.PostForm("topic"), []byte(c.PostForm("payload"))); err != nil {
		return
	}

}
